
#ifndef ASYNCCOMMANDHANDLER_H_
#define ASYNCCOMMANDHANDLER_H_

/**
* Template for asynchronous commands handling.
* Non pointer version
*/
template <class T> class RAsyncCommandHandler
    {
public: // Constructors and destructor

    /**
    * C++ default constructor.
    */
    RAsyncCommandHandler() : iPostCommandIdle( NULL ), iFromCallback( EFalse )
        {
        // No implementation required
        }

    /**
    * Destructor.
    */
    virtual ~RAsyncCommandHandler()
        {
        iCommandsArray.Reset();
        delete iPostCommandIdle;
        }

public: // New methods

    /**
    * Add a command to the handle command queue
    * @param aCommand command to add to the queue
    */
    void PostCommandL( const T& aCommand )
        {
        iCommandsArray.AppendL( aCommand );
        if ( !iFromCallback )
            {
            StartCommandQueueTimerL();
            }
        }

    /**
    * Stops the idle for performing asynchronous commands.
    */
    void StopCommandQueueTimer()
        {
        if ( iPostCommandIdle )
            {
            iPostCommandIdle->Cancel();
            }
        }

    /**
    * Resumes the idle for performing asynchronous commands.
    */
    void ResumeCommandQueueTimerL()
        {
        if ( !iFromCallback )
            {
            StartCommandQueueTimerL();
            }
        }

protected: // New methods

    /**
    * Command handler
    * @param aCommand command to handle
    */
    virtual void AsyncHandleCommandL( const T& aCommand ) = 0;

private: // New methods

    /**
    * Starts the idle for performing asynchronous commands.
    */
    void StartCommandQueueTimerL()
        {
        if ( !iPostCommandIdle )
            {
            iPostCommandIdle = CIdle::NewL( CIdle::EPriorityHigh );
            }

        if ( !iPostCommandIdle->IsActive() )
            {
            iPostCommandIdle->Start( TCallBack( PostCommandCallbackL, this ) );
            }
        }

    /**
    * Static callback for the commands post idle.
    * @param aPtr pointer to this instance
    */
    static TInt PostCommandCallbackL( TAny* aPtr )
        {
        TBool returnValue = ETrue;

        RAsyncCommandHandler* self = (RAsyncCommandHandler*) aPtr;
        self->iFromCallback = ETrue;

        if ( self->iCommandsArray.Count() )
            {
            self->AsyncHandleCommandL( self->iCommandsArray[0] );
            self->iCommandsArray.Remove( 0 );
            }

        if ( !self->iCommandsArray.Count() )
            {
            returnValue = EFalse;
            }

        self->iFromCallback = EFalse;
        return returnValue;
        }

private: // Member data

    /**
    * Array used as a queue for commands
    */
    RArray<T>            iCommandsArray;

    /**
    * Idle used for performing asynchronous commands.
    * Own
    */
    CIdle*              iPostCommandIdle;

    /**
    * Used to verify the post command origin
    */
    TBool               iFromCallback;
    };

/**
* Template for asynchronous commands handling.
* Pointer version
*/
template <class T> class RAsyncCommandHandler<T*>
    {
public: // Constructors and destructor

    /**
    * C++ default constructor.
    */
    RAsyncCommandHandler() : iPostCommandIdle( NULL ), iFromCallback( EFalse )
        {
        // No implementation required
        }

    /**
    * Destructor.
    */
    virtual ~RAsyncCommandHandler()
        {
        iCommandsArray.Reset();
        delete iPostCommandIdle;
        }

public: // New methods

    /**
    * Add a command to the handle command queue
    * @param aCommand command to add to the queue
    */
    void PostCommandL( T* aCommand )
        {
        if ( aCommand && KErrNotFound == iCommandsArray.Find( aCommand ) )
            {
            iCommandsArray.AppendL( aCommand );
            }
        if ( !iFromCallback )
            {
            StartCommandQueueTimerL();
            }
        }

    /**
    * Stops the idle for performing asynchronous commands.
    */
    void StopCommandQueueTimer()
        {
        if ( iPostCommandIdle )
            {
            iPostCommandIdle->Cancel();
            }
        }

    /**
    * Resumes the idle for performing asynchronous commands.
    */
    void ResumeCommandQueueTimerL()
        {
        if ( !iFromCallback )
            {
            StartCommandQueueTimerL();
            }
        }

protected: // New methods

    /**
    * Remove a command from the handle command queue
    * @param aCommand command to remove from the queue
    */
    void RemoveCommand( T* aCommand )
        {
        if ( aCommand )
            {
            TInt index = iCommandsArray.Find( aCommand );
            if ( KErrNotFound != index )
                {
                iCommandsArray.Remove( index );
                }
            }
        }

    /**
    * Command handler
    * @param aCommand command to handle
    */
    virtual void AsyncHandleCommandL( T& aCommand ) = 0;

private: // New methods

    /**
    * Starts the idle for performing asynchronous commands.
    */
    void StartCommandQueueTimerL()
        {
        if ( !iPostCommandIdle )
            {
            iPostCommandIdle = CIdle::NewL( CIdle::EPriorityHigh );
            }

        if ( !iPostCommandIdle->IsActive() )
            {
            iPostCommandIdle->Start( TCallBack( PostCommandCallbackL, this ) );
            }
        }

    /**
    * Static callback for the commands post idle.
    * @param aPtr pointer to this instance
    */
    static TInt PostCommandCallbackL( TAny* aPtr )
    {
        TBool returnValue = ETrue;

        RAsyncCommandHandler* self = (RAsyncCommandHandler*) aPtr;
        self->iFromCallback = ETrue;

        if ( self->iCommandsArray.Count() )
            {
            self->AsyncHandleCommandL( *self->iCommandsArray[0] );
            self->iCommandsArray.Remove( 0 );
            }

        if ( !self->iCommandsArray.Count() )
            {
            returnValue = EFalse;
            }

        self->iFromCallback = EFalse;
        return returnValue;
    }

private: // Member data

    /**
    * Array used as a queue for commands
    */
    RPointerArray<T> iCommandsArray;

    /**
    * Idle used for performing asynchronous commands.
    * Own
    */
    CIdle* iPostCommandIdle;

    /**
    * Used to verify the post command origin
    */
    TBool iFromCallback;
    };

#endif /* ASYNCCOMMANDHANDLER_H_ */
